import tushare as ts
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import matplotlib.animation as animation
from IPython.display import HTML
ts.set_token('1c7f85b9026518588c0d0cdac712c2d17344332c9c8cfe6bc83ee75c')
pro = ts.pro_api()

def get_financial_data(ts_code, start_date, end_date):
    """获取财务指标数据"""
    # 获取利润表数据
    income = pro.income(ts_code=ts_code, start_date=start_date, end_date=end_date,
                        fields='ts_code,ann_date,report_type,operate_profit,total_profit,n_income')

    # 获取资产负债表数据
    balance = pro.balancesheet(ts_code=ts_code, start_date=start_date, end_date=end_date,
                               fields='ts_code,ann_date,report_type,total_assets,total_liab,total_hldr_eqy_exc_min_int')

    # 获取现金流量表数据
    cashflow = pro.cashflow(ts_code=ts_code, start_date=start_date, end_date=end_date,
                            fields='ts_code,ann_date,report_type,n_cashflow_act')

    # 合并财务数据
    financial_data = pd.merge(income, balance, on=['ts_code', 'ann_date', 'report_type'])
    financial_data = pd.merge(financial_data, cashflow, on=['ts_code', 'ann_date', 'report_type'])

    # 转换为日期格式并排序
    financial_data['ann_date'] = pd.to_datetime(financial_data['ann_date'])
    financial_data = financial_data.sort_values('ann_date')

    return financial_data
# 获取贵州茅台财务数据
financial_data = get_financial_data('600519.SH', '20220101', '2025331')
print(financial_data.head())


def calculate_financial_ratios(financial_data):
    """计算财务比率"""
    ratios = financial_data.copy()

    # 计算盈利能力指标
    ratios['gross_margin'] = ratios['operate_profit'] / (ratios['operate_profit'] + ratios['total_profit'])
    ratios['net_margin'] = ratios['n_income'] / (ratios['operate_profit'] + ratios['total_profit'])
    ratios['roe'] = ratios['n_income'] / ratios['total_hldr_eqy_exc_min_int']

    # 计算偿债能力指标
    ratios['debt_to_equity'] = ratios['total_liab'] / ratios['total_hldr_eqy_exc_min_int']

    # 计算运营效率指标
    ratios['cash_flow_ratio'] = ratios['n_cashflow_act'] / ratios['total_assets']

    # 保留需要的列
    ratios = ratios[['ts_code', 'ann_date', 'gross_margin', 'net_margin',
                     'roe', 'debt_to_equity', 'cash_flow_ratio']]

    return ratios


# 计算财务比率
financial_ratios = calculate_financial_ratios(financial_data)
print(financial_ratios.head())
def get_stock_price(ts_code, start_date, end_date):
    """获取股票价格数据"""
    price_data = ts.pro_bar(ts_code=ts_code, adj='qfq', start_date=start_date, end_date=end_date)
    price_data['trade_date'] = pd.to_datetime(price_data['trade_date'])
    price_data = price_data.sort_values('trade_date')
    price_data.set_index('trade_date', inplace=True)
    return price_data

# 获取贵州茅台股价数据
price_data = get_stock_price('600519.SH', '20220101', '2025331')
print(price_data.head())

def financial_strategy(financial_ratios, price_data):
    """基于财务指标的交易策略"""
    # 合并财务数据和价格数据
    merged_data = pd.merge_asof(price_data.reset_index(),
                                financial_ratios.sort_values('ann_date'),
                                left_on='trade_date',
                                right_on='ann_date',
                                direction='backward')

    merged_data.set_index('trade_date', inplace=True)

    # 创建交易信号
    signals = pd.DataFrame(index=merged_data.index)
    signals['price'] = merged_data['close']

    # 策略逻辑：当多个财务指标同时表现良好时买入
    signals['signal'] = 0
    good_financials = (
            (merged_data['roe'] > 0.15) &
            (merged_data['debt_to_equity'] < 1) &
            (merged_data['net_margin'] > 0.2) &
            (merged_data['cash_flow_ratio'] > 0)
    )
    signals.loc[good_financials, 'signal'] = 1

    # 生成交易位置
    signals['positions'] = signals['signal'].diff()

    return signals


# 生成交易信号
signals = financial_strategy(financial_ratios, price_data)
print(signals.head())


def backtest_financial_strategy(signals, initial_capital=100000.0):
    """回测财务指标策略"""
    portfolio = pd.DataFrame(index=signals.index)
    portfolio['price'] = signals['price']
    portfolio['cash'] = initial_capital
    portfolio['shares'] = 0
    portfolio['total'] = initial_capital

    # 模拟交易
    for i in range(1, len(portfolio)):
        # 前一天的状态
        prev_cash = portfolio['cash'].iloc[i - 1]
        prev_shares = portfolio['shares'].iloc[i - 1]
        prev_price = portfolio['price'].iloc[i - 1]

        # 当前信号
        signal = signals['signal'].iloc[i]
        prev_signal = signals['signal'].iloc[i - 1]
        current_price = portfolio['price'].iloc[i]

        # 如果信号从0变为1，全仓买入
        if signal == 1 and prev_signal == 0:
            shares_to_buy = prev_cash // current_price
            portfolio.at[portfolio.index[i], 'shares'] = shares_to_buy
            portfolio.at[portfolio.index[i], 'cash'] = prev_cash - (shares_to_buy * current_price)

        # 如果信号从1变为0，全仓卖出
        elif signal == 0 and prev_signal == 1:
            portfolio.at[portfolio.index[i], 'cash'] = prev_cash + (prev_shares * current_price)
            portfolio.at[portfolio.index[i], 'shares'] = 0

        # 如果信号没有变化，保持仓位
        else:
            portfolio.at[portfolio.index[i], 'shares'] = prev_shares
            portfolio.at[portfolio.index[i], 'cash'] = prev_cash

        # 计算总资产价值
        portfolio.at[portfolio.index[i], 'total'] = (
                portfolio['cash'].iloc[i] + (portfolio['shares'].iloc[i] * current_price)
        )

    # 计算收益率
    portfolio['returns'] = portfolio['total'].pct_change()

    return portfolio


# 回测策略
portfolio = backtest_financial_strategy(signals)
print(portfolio.tail())

def evaluate_strategy(portfolio):
    """评估策略表现"""
    returns = portfolio['returns']

    # 计算关键指标
    cumulative_return = (1 + returns).cumprod()[-1] - 1
    annual_return = returns.mean() * 252
    volatility = returns.std() * np.sqrt(252)
    sharpe_ratio = annual_return / volatility

    # 最大回撤
    cumulative_returns = (1 + returns).cumprod()
    peak = cumulative_returns.expanding(min_periods=1).max()
    drawdown = (cumulative_returns - peak) / peak
    max_drawdown = drawdown.min()

    print(f"策略表现评估:")
    print(f"累计收益率: {cumulative_return:.2%}")
    print(f"年化收益率: {annual_return:.2%}")
    print(f"年化波动率: {volatility:.2%}")
    print(f"夏普比率: {sharpe_ratio:.2f}")
    print(f"最大回撤: {max_drawdown:.2%}")
    # 绘制结果
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
    plt.figure(figsize=(12, 8))
    # 绘制资产曲线
    plt.subplot(2, 1, 1)
    plt.plot(portfolio['total'], label='投资组合价值')
    plt.title('投资组合表现')
    plt.ylabel('价值 （RMB）')
    plt.legend()

    # 绘制收益率
    plt.subplot(2, 1, 2)
    plt.plot(returns.cumsum(), label='累计收益率')
    plt.ylabel('累计收益率')
    plt.legend()

    plt.tight_layout()
    plt.show()

# 评估策略
evaluate_strategy(portfolio)